package com.yuchs.test.log4j;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.appender.db.nosql.NoSQLProvider;
import org.apache.logging.log4j.core.appender.db.nosql.mongo.MongoDBConnection;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttr;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.status.StatusLogger;

import com.mongodb.DB;
import com.mongodb.MongoClient;
import com.mongodb.WriteConcern;
import com.yuchs.test.log4j.common.CommUtils;

@Plugin(name = "PlayerLogDB", category = "Core", printObject = true)
public class PlayerLogProvider implements NoSQLProvider<MongoDBConnection> {

	private static final String fsm_playerLogName = "PlayerLogLogger";
	
	/**
	 * get the player log logger for record the player information log to 
	 * remote mongodb
	 * @return player logger
	 */
	public static Logger getPlayerLog(){
		return LogManager.getLogger(fsm_playerLogName);
	}
	
	private static final Logger LOGGER = StatusLogger.getLogger();
	
	private final String collectionName;
    private final DB database;
    private final WriteConcern writeConcern;
    
    private PlayerLogProvider(final String _collectionName,final DB _database,final WriteConcern _writeConcern){
    	collectionName	= _collectionName;
    	database 		= _database;
    	writeConcern	= _writeConcern;    	
    }

	@PluginFactory
	public static PlayerLogProvider createNoSQLProvider(@PluginAttr("collectionName") final String collectionName,
	                                                  @PluginAttr("writeConcern") final String writeConcern,
	                                                  @PluginAttr("databaseName") final String databaseName,
	                                                  @PluginAttr("server") final String server,
	                                                  @PluginAttr("port") final String port,
	                                                  @PluginAttr("username") final String username,
	                                                  @PluginAttr("password") final String password) {
		DB db;
		if(CommUtils.isNullOrEmpty(databaseName) || CommUtils.isNullOrEmpty(collectionName)){
			LOGGER.error("databaseName and collectionName cannot be null");
			return null;
		}

		try{

			if(CommUtils.isNullOrEmpty(server)){
				db = new MongoClient().getDB(databaseName);
			}else{
				if(CommUtils.isNullOrEmpty(port)){
					db = new MongoClient(server).getDB(databaseName);
				}else{
					db = new MongoClient(server,Integer.parseInt(port)).getDB(databaseName);
				}
			}
			
			if(!db.isAuthenticated()){
				if(CommUtils.isNullOrEmpty(username) || CommUtils.isNullOrEmpty(password)){
					LOGGER.error("mongodb need auth but no username or password");
					return null;
				}
				
				if(!db.authenticate(username, password.toCharArray())){
					LOGGER.error("mongodb cannot auth with username '{}' and password'{}'",username,password);
					return null;
				}
			}
			
		}catch(final Exception e){
			LOGGER.error("mongo database init failed!",e);
			return null;
		}
		
		WriteConcern wc;
        if (CommUtils.isNullOrEmpty(writeConcern)){
        	wc = WriteConcern.ACKNOWLEDGED;
        } else {
        	wc = WriteConcern.valueOf(writeConcern);
        	if(wc == null){
        		LOGGER.error("unknown writeConcern '{}'", writeConcern);
        		wc = WriteConcern.ACKNOWLEDGED;
        	}   
        }
		
		return new PlayerLogProvider(collectionName, db, wc);
	}
	
	@Override
    public MongoDBConnection getConnection() {
        return new MongoDBConnection(database,writeConcern,collectionName);
    }

}
